package com.fish.web.aspect;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fish.common.util.JwtUtil;
import com.fish.dao.mapper.OperationLogMapper;
import com.fish.model.entity.OperationLog;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * 操作日志AOP切面
 */
@Slf4j
@Aspect
@Component
public class OperationLogAspect {
    
    @Autowired
    private OperationLogMapper operationLogMapper;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    /**
     * 环绕通知，记录操作日志
     */
    @Around("@annotation(com.fish.common.annotation.OperationLog)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        
        // 获取请求信息
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes != null ? attributes.getRequest() : null;
        
        // 创建操作日志对象
        OperationLog operationLog = new OperationLog();
        
        try {
            // 获取注解信息
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            com.fish.common.annotation.OperationLog annotation = method.getAnnotation(com.fish.common.annotation.OperationLog.class);
            
            // 设置操作描述
            if (annotation != null) {
                operationLog.setOperation(annotation.value());
            }
            
            // 设置请求方法
            String className = joinPoint.getTarget().getClass().getName();
            String methodName = signature.getName();
            operationLog.setMethod(className + "." + methodName);
            
            // 设置请求参数
            Object[] args = joinPoint.getArgs();
            try {
                String params = objectMapper.writeValueAsString(args);
                // 限制参数长度
                if (params.length() > 2000) {
                    params = params.substring(0, 2000) + "...";
                }
                operationLog.setParams(params);
            } catch (Exception e) {
                operationLog.setParams("参数序列化失败");
            }
            
            // 获取用户信息
            if (request != null) {
                String token = request.getHeader("Authorization");
                if (token != null && token.startsWith("Bearer ")) {
                    token = token.substring(7);
                    try {
                        Long userId = JwtUtil.getUserId(token);
                        String username = JwtUtil.getUsername(token);
                        operationLog.setUserId(userId);
                        operationLog.setUsername(username);
                    } catch (Exception e) {
                        log.warn("解析Token失败:", e);
                    }
                }
                
                // 获取IP地址
                operationLog.setIp(getIpAddress(request));
                
                // 获取User-Agent
                String userAgent = request.getHeader("User-Agent");
                if (userAgent != null && userAgent.length() > 500) {
                    userAgent = userAgent.substring(0, 500);
                }
                operationLog.setUserAgent(userAgent);
            }
            
            // 执行方法
            Object result = joinPoint.proceed();
            
            // 记录成功
            operationLog.setResult("success");
            
            return result;
            
        } catch (Throwable e) {
            // 记录失败
            operationLog.setResult("error");
            String errorMsg = e.getMessage();
            if (errorMsg != null && errorMsg.length() > 1000) {
                errorMsg = errorMsg.substring(0, 1000);
            }
            operationLog.setErrorMsg(errorMsg);
            
            throw e;
            
        } finally {
            // 计算执行时长
            long endTime = System.currentTimeMillis();
            operationLog.setExecutionTime(endTime - startTime);
            operationLog.setCreateTime(LocalDateTime.now());
            
            // 异步保存日志（避免影响主业务）
            try {
                operationLogMapper.insert(operationLog);
            } catch (Exception e) {
                log.error("保存操作日志失败:", e);
            }
        }
    }
    
    /**
     * 获取客户端IP地址
     */
    private String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}